<template>
  <div>
    <canvas id="canvas" width="1960px" height="1200px" @onload="initBg()"></canvas>
    <canvas id="canvasbg" width="1960px" height="1200px"></canvas>
  </div>
</template>

<script>
export default {
  name: 'loginMoviebg',
  data () {
    return {}
  },
  computed: {},
  methods: {
    initBg: function () {
      let canvas = $('#canvas')[0]
      // min and max radius, radius threshold and percentage of filled circles
      const radMin = 5

      const radMax = 125

      const filledCircle = 60
      // percentage of filled circles

      const concentricCircle = 30
      // percentage of concentric circles

      const radThreshold = 25 // IFF special, over this radius concentric, otherwise filled
      // min and max speed to move
      const speedMin = 0.3

      const speedMax = 2.5
      // max reachable opacity for every circle and blur effect
      const maxOpacity = 0.6
      // default palette choice
      let colors = ['52,168,83', '117,95,147', '199,108,23', '194,62,55', '0,172,212', '120,120,120']

      let bgColors = ['52,168,83', '117,95,147', '199,108,23', '194,62,55', '0,172,212', '120,120,120']

      const circleBorder = 10

      let backgroundMlt = 0.85
      // min distance for links
      let linkDist = Math.min(canvas.width, canvas.height) / 2.4

      const lineBorder = 2.5
      // most importantly: number of overall circles and arrays containing them
      const maxCircles = 12

      let points = []

      let pointsBack = []

      // populating the screen
      for (let i = 0; i < maxCircles * 2; i++) points.push(new Circle())
      for (let i = 0; i < maxCircles; i++) pointsBack.push(new Circle(true))

      // experimental vars
      let circleExp = 1

      const circleExpMax = 1.003

      const circleExpMin = 0.997

      let circleExpSp = 0.00004

      let circlePulse = false

      // circle class
      function Circle (background) {
        // if background, it has different rules
        this.background = (background || false)
        this.x = randRange(-canvas.width / 2, canvas.width / 2)
        this.y = randRange(-canvas.height / 2, canvas.height / 2)
        this.radius = background ? hyperRange(radMin, radMax) * backgroundMlt : hyperRange(radMin, radMax)
        this.filled = this.radius < radThreshold ? (randint(0, 100) > filledCircle ? false : 'full') : (randint(0, 100) > concentricCircle ? false : 'concentric')
        this.color = background ? bgColors[randint(0, bgColors.length - 1)] : colors[randint(0, colors.length - 1)]
        this.borderColor = background ? bgColors[randint(0, bgColors.length - 1)] : colors[randint(0, colors.length - 1)]
        this.opacity = 0.05
        this.speed = (background ? randRange(speedMin, speedMax) / backgroundMlt : randRange(speedMin, speedMax)) // * (radMin / this.radius);
        this.speedAngle = Math.random() * 2 * Math.PI
        this.speedx = Math.cos(this.speedAngle) * this.speed
        this.speedy = Math.sin(this.speedAngle) * this.speed
        let spacex = Math.abs((this.x - (this.speedx < 0 ? -1 : 1) * (canvas.width / 2 + this.radius)) / this.speedx)

        let spacey = Math.abs((this.y - (this.speedy < 0 ? -1 : 1) * (canvas.height / 2 + this.radius)) / this.speedy)
        this.ttl = Math.min(spacex, spacey)
      }

      Circle.prototype.init = function () {
        Circle.call(this, this.background)
      }

      // support functions
      // generate random int a<=x<=b
      function randint (a, b) {
        return Math.floor(Math.random() * (b - a + 1) + a)
      }

      // generate random float
      function randRange (a, b) {
        return Math.random() * (b - a) + a
      }

      // generate random float more likely to be close to a
      function hyperRange (a, b) {
        return Math.random() * Math.random() * Math.random() * (b - a) + a
      }

      // rendering function
      function drawCircle (ctx, circle) {
        // circle.radius *= circleExp;
        let radius = circle.background ? circle.radius *= circleExp : circle.radius /= circleExp
        ctx.beginPath()
        ctx.arc(circle.x, circle.y, radius * circleExp, 0, 2 * Math.PI, false)
        ctx.lineWidth = Math.max(1, circleBorder * (radMin - circle.radius) / (radMin - radMax))
        ctx.strokeStyle = ['rgba(', circle.borderColor, ',', circle.opacity, ')'].join('')
        if (circle.filled === 'full') {
          ctx.fillStyle = ['rgba(', circle.borderColor, ',', circle.background ? circle.opacity * 0.8 : circle.opacity, ')'].join('')
          ctx.fill()
          ctx.lineWidth = 0
          ctx.strokeStyle = ['rgba(', circle.borderColor, ',', 0, ')'].join('')
        }
        ctx.stroke()
        if (circle.filled === 'concentric') {
          ctx.beginPath()
          ctx.arc(circle.x, circle.y, radius / 2, 0, 2 * Math.PI, false)
          ctx.lineWidth = Math.max(1, circleBorder * (radMin - circle.radius) / (radMin - radMax))
          ctx.strokeStyle = ['rgba(', circle.color, ',', circle.opacity, ')'].join('')
          ctx.stroke()
        }
        circle.x += circle.speedx
        circle.y += circle.speedy
        if (circle.opacity < (circle.background ? maxOpacity : 1)) circle.opacity += 0.01
        circle.ttl--
      }

      // initializing function
      function init () {
        window.requestAnimationFrame(draw)
      }

      // rendering function
      function draw () {
        if (circlePulse) {
          if (circleExp < circleExpMin || circleExp > circleExpMax) {
            circleExpSp *= -1
          }
          circleExp += circleExpSp
        }
        let ctxfr = document.getElementById('canvas').getContext('2d')
        let ctxbg = document.getElementById('canvasbg').getContext('2d')

        ctxfr.globalCompositeOperation = 'destination-over'
        ctxfr.clearRect(0, 0, canvas.width, canvas.height) // clear canvas
        ctxbg.globalCompositeOperation = 'destination-over'
        ctxbg.clearRect(0, 0, canvas.width, canvas.height) // clear canvas

        ctxfr.save()
        ctxfr.translate(canvas.width / 2, canvas.height / 2)
        ctxbg.save()
        ctxbg.translate(canvas.width / 2, canvas.height / 2)

        // function to render each single circle, its connections and to manage its out of boundaries replacement
        function renderPoints (ctx, arr) {
          for (let i = 0; i < arr.length; i++) {
            let circle = arr[i]
            // checking if out of boundaries
            if (circle.ttl < 0) {
            }

            if (circle.ttl < -20) arr[i].init(arr[i].background)
            drawCircle(ctx, circle)
          }
          for (let i = 0; i < arr.length - 1; i++) {
            for (let j = i + 1; j < arr.length; j++) {
              let deltax = arr[i].x - arr[j].x
              let deltay = arr[i].y - arr[j].y
              let dist = Math.pow(Math.pow(deltax, 2) + Math.pow(deltay, 2), 0.5)
              // if the circles are overlapping, no laser connecting them
              if (dist <= arr[i].radius + arr[j].radius) continue
              // otherwise we connect them only if the dist is < linkDist
              if (dist < linkDist) {
                let xi = (arr[i].x < arr[j].x ? 1 : -1) * Math.abs(arr[i].radius * deltax / dist)
                let yi = (arr[i].y < arr[j].y ? 1 : -1) * Math.abs(arr[i].radius * deltay / dist)
                let xj = (arr[i].x < arr[j].x ? -1 : 1) * Math.abs(arr[j].radius * deltax / dist)
                let yj = (arr[i].y < arr[j].y ? -1 : 1) * Math.abs(arr[j].radius * deltay / dist)
                ctx.beginPath()
                ctx.moveTo(arr[i].x + xi, arr[i].y + yi)
                ctx.lineTo(arr[j].x + xj, arr[j].y + yj)
                ctx.strokeStyle = ['rgba(', arr[i].borderColor, ',', Math.min(arr[i].opacity, arr[j].opacity) * ((linkDist - dist) / linkDist), ')'].join('')
                ctx.lineWidth = (arr[i].background ? lineBorder * backgroundMlt : lineBorder) * ((linkDist - dist) / linkDist) //* ((linkDist-dist)/linkDist);
                ctx.stroke()
              }
            }
          }
        }

        renderPoints(ctxfr, points)
        renderPoints(ctxbg, pointsBack)

        ctxfr.restore()
        ctxbg.restore()

        window.requestAnimationFrame(draw)
      }

      init()
    }
  },
  mounted: function () {
    // 初始化动态背景图
    this.initBg()
  }
}
</script>

<style scoped>
  /* bgmovie style start */
  canvas {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 2;
    width: 1950px;
    height: auto;
  }

  #canvas {
    z-index: 2;
    opacity: 0.8;
  }

  #canvasbg {
    z-index: 1;
    filter: blur(3px);
    opacity: 0.6;
  }

  /* bgmovie style end */
</style>
